use Test;

### FieldsEntity Test:
### ==================
## Test that the tested object is a correctly created entity of the specified type

package FieldsTest;
## Keys for accessing the container:
#-----------------------------------
# TESTED_OBJ: Actual created object under test
# TESTED_OBJ_FIELDS_ARRAY: Array of keys that should correspond to array references in the tested object
# TESTED_OBJ_FIELDS_HASH: Array of keys that should correspond to hash references in the tested object
# TESTED_OBJ_FIELDS_OTHER_REF: Array of keys that should correspond to references of other types than hash or array in the tested object
# TESTED_OBJ_FIELDS_SCALARS: Array of keys that should correspond to scalars in the tested object (should be defined and not be a reference)

@ISA = qw/Test/;

our @DEPENDS_ON = qw/creation/;

sub init{
    my $self = shift;
}

sub setup{
    my $self = shift;
}

sub run{
    my $self = shift;

    my $obj = $self->component("TESTED_OBJ");
    my $hashes_ref     = $self->component("TESTED_OBJ_FIELDS_HASHES");
    my $arrays_ref     = $self->component("TESTED_OBJ_FIELDS_ARRAYS");
    my $others_ref  = $self->component("TESTED_OBJ_FIELDS_ARRAYS");
    my $scalars_ref    = $self->component("TESTED_OBJ_FIELDS_SCALARS");

    $self->log("Retrieving object: ".$obj);
    my $entity_type = $obj->type;

    my $hashes_failed  = 0;
    my $arrays_failed  = 0;
    my $others_failed  = 0;
    my $scalars_failed = 0;


    if(defined($hashes_ref) && (ref $hashes_ref eq "ARRAY")){
	my @hashes  = @{$hashes_ref};
	$self->log("Checking for HASHES: (".(join ",", @hashes).")");
	$hashes_failed = $self->checkFields($obj, "HASH", \@hashes);
    }else{
	$self->log("Skipping check for HASHES");
    }

    if(defined($arrays_ref) && (ref $arrays_ref eq "ARRAY")){
	my @arrays = @{$arrays_ref};
	$self->log("Checking for ARRAYS: (".(join ",", @arrays).")");
	$arrays_failed = $self->checkFields($obj, "ARRAY", \@arrays);
    }else{
	$self->log("Skipping check for ARRAYS");
    }

    if(defined($others_ref) && (ref $others_ref eq "ARRAY")){
	my @others = @{$others_ref};
	$self->log("Checking for OTHER REFERENCES: (".(join ",", @others).")");
	$others_failed = $self->checkFields($obj, "", \@others, 1);
    }else{
	$self->log("Skipping check for OTHER REFERENCES");
    }

    if(defined($scalars_ref) && (ref $scalars_ref eq "ARRAY")){
	my @scalars = @{$scalars_ref};
	$self->log("Checking for SCALARS: (".(join ",", @scalars).")");
	$scalars_failed = $self->checkFields($obj, "", \@scalars);
    }else{
	$self->log("Skipping check for SCALARS");
    }

    $self->assertFalse($scalars_failed, "SCALAR_FIELDS");
    $self->assertFalse($arrays_failed, "ARRAY_FIELDS");
    $self->assertFalse($hashes_failed, "HASH_FIELDS");
    $self->assertFalse($others_failed, "OTHER_REF_FIELDS");
}

sub teardown{
    my $self = shift;
}


# If neq = 0 it checks expectedRef eq field ref type
# Otherwise, it checks expectedRef neq field ref type
sub checkFields{
    my $self = shift;
    my $obj  = shift;
    my $expectedRef = shift;
    my $expected_fields_ref = shift;
    my @expected_fields = @{$expected_fields_ref};

    my $neq = shift; 
    $neq = 0 unless(defined $neq);

    my $failed = 0;

    foreach(@expected_fields){
	my $field = $obj->{$_};

	if(!defined $field){
	    $self->log("---For field name ".$_."; Field not found (was undefined)");
	    $failed = 1;
	    next;
	}

	if($neq == 0){
	    if(ref $field ne $expectedRef){
		$self->log("---For field name ".$_." found ".(ref $_)." expected ".$expectedRef);
		$failed = 1;
	    }
	}else{
	    if(ref $field eq $expectedRef){
		$self->log("---For field name ".$_." found ".(ref $_)." expected different");
		$failed = 1;
	    }
	}
    } # for all expected hashes
    
    return $failed;
}
1;
